# -*- coding: utf-8 -*-
import ast
import hashlib
import json
import math
from collections import OrderedDict

import requests
from django.conf import settings

from async import async_job
from common.agentpay.base import AbstractHandler
from common.agentpay.db import get_agent_pay_order
from common.agentpay.model import AGENT_PAY_STATUS
from common.cache import redis_cache
from common.channel import admin_db as channel_admin_db
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import ParamError
from common.utils.types import Enum
from common.utils.tz import local_now

_LOGGER = track_logging.getLogger(__name__)

_GATEWAY = 'http://gateway.fubaohe.com/gateway/scanPay/payH5'
_UNION_GATEWAY = 'http://gateway.fubaohe.com/gateway/scanPay/payFast'
_QQ_GATEWAY = 'http://gateway.fubaohe.com/gateway/scanPay/payWap'
_JD_GATEWAY = 'http://gateway.fubaohe.com/gateway/scanPay/payWap'
_ALI_GATEWAY = 'http://gateway.fubaohe.com/gateway/scanPay/payService'

# 杭州侨首贸易有限公司 QQwap，京东H5，银联快捷
# 商户帐号：15611313464
# 商户密码：a123456（请及时修改原始密码）
# 商户KEY：e30341757d5048118d2b5fff6ec9dffe
# 商户密钥：860ada80227c4307b890a7f945a93460
#
# 北京鸿创远大商贸有限公司
# 商户帐号：15652143156
# 商户密码：a123456（请及时修改原始密码）
# 商户KEY：94eca370799c461b9059c2c407b8c5f7
# 商户密钥：01a734d5383b41728a20279dde9ba2c1
#
# 河南国福网络科技有限公司
# 商户帐号：13020070742
# 商户密码：a123456（请及时修改原始密码）
# 商户KEY：35e4ef3b6f9448c3be7e41f1b54c81a7
# 商户密钥：ec70dbc4148e4d34ae27fb3a0df19584
APP_CONF = {
    '77dd4f1b1fd74879911a91801bfcbe02': {
        # kvpay云闪付   loki
        'API_KEY': '326a140bc55e446eabf39898d201401f'
    },
    'e30341757d5048118d2b5fff6ec9dffe': {
        'API_KEY': '860ada80227c4307b890a7f945a93460'
    },
    '94eca370799c461b9059c2c407b8c5f7': {
        'API_KEY': '01a734d5383b41728a20279dde9ba2c1'
    },
    '35e4ef3b6f9448c3be7e41f1b54c81a7': {
        'API_KEY': 'ec70dbc4148e4d34ae27fb3a0df19584'
    },
    '18': {
        'API_KEY': 'HroEd76AsuFfX3FTV5PbtNnh97tRIM47dDRD',
        'draw_gateway': 'http://cz.627pay.com/api/pay',
        'draw_query_gateway': 'http://cz.627pay.com/api/query_pay',
        'balance_query_gateway': 'http://cz.627pay.com/api/query_pay_balance',
    },
}


def _get_api_key(mch_id):
    return APP_CONF[mch_id]['API_KEY']


def _get_draw_gateway(mch_id):
    return APP_CONF[mch_id]['draw_gateway']


def _get_draw_query_gateway(mch_id):
    return APP_CONF[mch_id]['draw_query_gateway']


def _get_balance_gateway(mch_id):
    return APP_CONF[mch_id]['balance_query_gateway']


def generate_sign(parameter, key):
    s = ''
    for k in sorted(parameter.keys()):
        s += '%s=%s&' % (k, parameter[k])
    s += 'paySecret=%s' % key
    _LOGGER.info("kvpay sign string is: %s", s)
    m = hashlib.md5()
    m.update(s.encode('utf8'))
    sign = m.hexdigest().upper()
    return sign


def generate_draw_sign(parameter, key):
    s = ''
    for k in sorted(parameter.keys()):
        s += '%s=%s&' % (k, parameter[k])
    s += 'apiKey=%s' % key
    _LOGGER.info("kvpay sign string is: %s", s)
    m = hashlib.md5()
    m.update(s)
    sign = m.hexdigest().upper()
    return sign


def generate_draw_notify_sign(parameter, key):
    s = ''
    for k in sorted(parameter.keys()):
        s += '%s=%s&' % (k, parameter[k])
    s += 'apiKey=%s' % key
    _LOGGER.info("kvpay sign string is: %s", s)
    m = hashlib.md5()
    m.update(s.encode('utf8'))
    sign = m.hexdigest().upper()
    return sign


def verify_notify_sign(params, key):
    sign = params['sign']
    params.pop('sign')
    calculated_sign = generate_sign(params, key)
    if sign != calculated_sign:
        _LOGGER.info("kvpay sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


def verify_draw_notify_sign(params, key):
    sign = params['Sign']
    params.pop('Sign')
    calculated_sign = generate_draw_notify_sign(params, key)
    if sign != calculated_sign:
        _LOGGER.info("kvpay sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


def build_form(params):
    if params['payWayCode'] == 'SCAN_FAST':
        gateway = _UNION_GATEWAY
    elif params['payWayCode'] == 'SCAN_QQ_WAP':
        gateway = _QQ_GATEWAY
    elif params['payWayCode'] == 'SCAN_JD_WAP':
        gateway = _JD_GATEWAY
    else:
        gateway = _GATEWAY

    _LOGGER.info("gateway is: %s", gateway)

    html = u"<head><title>loading...</title></head><form id='kvpaysubmit' name='kvpaysubmit' action='" + gateway + "' method='post'>"
    for k, v in params.items():
        html += "<input type='hidden' name='%s' value='%s'/>" % (k, v)
    html += "</form>"
    html += "<script>document.forms['kvpaysubmit'].submit();</script>"
    return html


def _get_pay_type(service):
    if service == 'alipay':
        return 'SCAN_ALIPAY_WAP'
    elif service == 'union':
        return 'SCAN_FAST'
    elif service == 'quick':
        return 'SCAN_YL_H5'
    elif service == 'qq':
        return 'SCAN_QQ_WAP'
    elif service == 'jd':
        return 'SCAN_JD_WAP'
    else:
        return 'SCAN_WEIXIN_H5'


def _get_way_code(service):
    if service == 'cloud_flash':
        return 'SCAN_YL'
    else:
        return 'SCAN_WEIXIN_H5'


def create_charge(pay, pay_amount, info):
    service = info['service']
    if service in ['wechat', 'alipay']:
        return create_wechat_or_alipay_charge(pay, pay_amount, info)
    else:
        return create_cloud_flash_charge(pay, pay_amount, info)


def create_wechat_or_alipay_charge(pay, pay_amount, info):
    ''' 创建订单 '''
    service = info['service']  # wechat or alipay

    pay_type = _get_pay_type(service)
    app_id = info['app_id']
    api_key = _get_api_key(app_id)
    p_dict = OrderedDict((
        ('orderNo', str(pay.id)),
        ('productName', 'pay'),
        ('orderPeriod', '24'),
        ('orderPrice', '%.2f' % math.ceil(pay_amount)),
        ('payWayCode', pay_type),
        ('osType', '1'),  # 0(pc端) 1(移动端)
        ('notifyUrl', '{}/pay/api/{}/kvpay/{}'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
        ('payKey', app_id),
        ('field1', 'charge'),
    ))

    if pay_type in ['SCAN_WEIXIN_H5', 'SCAN_ALIPAY_WAP', 'SCAN_YL_H5']:
        p_dict['sceneType'] = '2'
        p_dict['wapUrl'] = settings.NOTIFY_PREFIX
        p_dict['wapName'] = settings.NOTIFY_PREFIX

    p_dict['sign'] = generate_sign(p_dict, api_key)
    _LOGGER.info('kvpay before data: %s', json.dumps(p_dict))
    html_text = build_form(p_dict)
    cache_id = redis_cache.save_html(pay.id, html_text)
    charge_resp = {
        'charge_info': settings.PAY_CACHE_URL + cache_id,
    }
    return charge_resp


def create_cloud_flash_charge(pay, pay_amount, info):
    ''' 创建订单 '''
    service = info['service']
    app_id = info['app_id']
    api_key = _get_api_key(app_id)
    p_dict = OrderedDict((
        ('orderNo', str(pay.id)),
        ('productName', 'pay'),
        ('orderPeriod', '24'),
        ('orderPrice', '%.2f' % math.ceil(pay_amount)),
        ('payWayCode', _get_way_code(service)),
        ('osType', '1'),  # 0(pc端) 1(移动端)
        ('notifyUrl', '{}/pay/api/{}/kvpay/{}'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
        ('payKey', app_id),
        ('field1', 'charge'),
    ))
    p_dict['sign'] = generate_sign(p_dict, api_key)
    _LOGGER.info('kvpay before data: %s', json.dumps(p_dict))
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_ALI_GATEWAY, data=p_dict, headers=headers, timeout=3)
    _LOGGER.info("kvpay create rsp data: %s", response.text)
    return {'charge_info': json.loads(response.text)['payURL']}


def check_notify_sign(request, app_id):
    data = dict(request.GET.iteritems())
    api_key = _get_api_key(app_id)
    _LOGGER.info("kvpay notify data: %s", data)
    verify_notify_sign(data, api_key)
    pay_id = data['orderNo']
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s" % data)
        raise ParamError('kvpay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    mch_id = pay.mch_id
    trade_status = data['tradeStatus']
    trade_no = data.get('trxNo')
    total_fee = float(data['orderPrice'])

    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }

    from common.channel.pay import check_channel_order
    check_channel_order(pay_id, total_fee, app_id)
    if trade_status == 'SUCCESS':
        _LOGGER.info('kvpay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)

    async_job.notify_mch(pay_id)


_QUERY_GATEWAY = 'http://www.kvpay.com/gateway/scanPay/orderQuery'


def query_charge(pay_order, app_id):
    ''' 查询订单 '''
    api_key = _get_api_key(app_id)
    p_dict = OrderedDict((
        ('orderNo', pay_order.id),
        ('payKey', app_id),
    ))
    p_dict['sign'] = generate_sign(p_dict, api_key)
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_QUERY_GATEWAY, data=p_dict, headers=headers, timeout=3)
    _LOGGER.info('kvpay query, %s', response.text)
    if response.status_code == 200:
        # response text is a pure html text
        data = json.loads(response.text)
        # verify_notify_sign(data, api_key) 签名不通过
        mch_id = pay_order.mch_id
        trade_status = data['tradeStatus']
        total_fee = float(data['orderPrice'])
        trade_no = pay_order.id

        extend = {
            'trade_status': trade_status,
            'total_fee': total_fee
        }

        if trade_status == 'SUCCESS' and total_fee > 0:
            _LOGGER.info('kvpay query order success, mch_id:%s pay_id:%s' % (mch_id, pay_order.id))
            res = order_db.add_pay_success(pay_order.mch_id, pay_order.id,
                                           total_fee, trade_no, extend)
            if res:
                # async notify
                async_job.notify_mch(pay_order.id)


def _get_bank_type(bank_type):
    if bank_type == 'ICBC':
        return 'ICBC'
    elif bank_type == 'CCB':
        return 'CCB'
    elif bank_type == 'PNB':
        return 'PAB'
    elif bank_type == 'BOC':
        return 'BOC'
    elif bank_type == 'ABC':
        return 'ABC'
    elif bank_type == 'BCM':
        return 'BOCOM'
    elif bank_type == 'CMB':
        return 'CMB'
    elif bank_type == 'CNCB':
        return 'CITIC'
    elif bank_type == 'CEB':
        return 'CEB'
    elif bank_type == 'HXB':
        return 'HXB'
    elif bank_type == 'SPDB':
        return 'SPDB'
    elif bank_type == 'CIB':
        return 'CIB'
    elif bank_type == 'CMBC':
        return 'CMBC'
    elif bank_type == 'CGB':
        return 'CGB'
    elif bank_type == 'PSBC':
        return 'PSBC'
    else:
        return 'THIRD_NOT_SUPPORT'


NOTIFY_PAY_STATUS = Enum({
    "WAIT": (0, u"等待"),
    "SUCCESS": (1, u"成功"),
    "FAIL": (2, u"失败"),
})


def convert_notify_status(status):
    if status == NOTIFY_PAY_STATUS.SUCCESS:
        return AGENT_PAY_STATUS.SUCCESS
    elif status == NOTIFY_PAY_STATUS.FAIL:
        return AGENT_PAY_STATUS.FAIL
    elif status == NOTIFY_PAY_STATUS.WAIT:
        return AGENT_PAY_STATUS.SUBMIT


class KvPayHandler(AbstractHandler):

    def submit_order(self, order_no):
        """
        创建代付请求
        :return:
        """
        agent_pay = get_agent_pay_order(order_no)
        chn = channel_admin_db.get_channel(int(agent_pay.channel_id))

        chn_info = json.loads(chn.info)
        app_id = chn_info['app_id']
        params = {
            'MerchantNo': app_id,
            'OrderPrice': '%.2f' % agent_pay.total_fee,
            'OutOrderNo': agent_pay.order_no,
            'TradeTime': local_now().strftime('%Y-%m-%d %H:%M:%S'),
            'UserType': '1',
            'AccountNo': agent_pay.card_no,
            'AccountName': agent_pay.account_name,
            'BankNo': _get_bank_type(agent_pay.bank_code),
            'Issuer': agent_pay.unionpay_no,
            'ApiNotifyUrl': '{}/pay/api/{}/kvpay/'.format(settings.NOTIFY_PREFIX, settings.AGENT_PAY_NOTIFY_PATH),
        }
        params['Sign'] = generate_draw_sign(params, _get_api_key(app_id))
        _LOGGER.info('kvpay draw data: %s', json.dumps(params))
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        response = requests.post(_get_draw_gateway(app_id), data=params, timeout=3, headers=headers, verify=False)
        _LOGGER.info("kvpay draw rsp data: %s %s", response.status_code, response.text)
        data = json.loads(response.text)

        if data['resultCode'] == '0000':
            return params['OutOrderNo'], '', '代付成功->' + str(response.text)
        else:
            return params['OutOrderNo'], '', '代付失败->' + str(response.text)

    def agent_pay_notify(self, order_no, status, pay_fee):
        """
        代付到账回调
        :return:
        """
        order = get_agent_pay_order(order_no)
        assert int(status) in (NOTIFY_PAY_STATUS.SUCCESS, NOTIFY_PAY_STATUS.FAIL)
        status = convert_notify_status(status)
        self.agent_pay_callback(order_no, status)

    def query_agent_pay(self, order_no):
        """
        查询代付请求
        :return:
        """
        agent_pay = get_agent_pay_order(order_no)
        chn = channel_admin_db.get_channel(int(agent_pay.channel_id))
        chn_info = json.loads(chn.info)
        app_id = chn_info['app_id']
        params = {
            'MerchantNo': app_id,
            'OutTradeNo': agent_pay.order_no,
        }
        params['Sign'] = generate_draw_sign(params, _get_api_key(app_id))
        _LOGGER.info('kvpay draw query data: %s', json.dumps(params))
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        response = requests.post(_get_draw_query_gateway(app_id), data=params, timeout=3, headers=headers, verify=False)
        _LOGGER.info("kvpay draw query rsp data: %s %s", response.status_code, response.text)
        if response.status_code != 200:
            raise ParamError('kvpay query_agent_pay error')
        data = json.loads(response.text)['data']
        if data['order_status'] == 'WAITING_PAYMENT':
            results = '代付处理中->' + str(response.text)
        elif data['order_status'] == 'FAILED':
            results = '代付失败->' + str(response.text)
        elif data['order_status'] == 'SUCCESS':
            results = '代付成功->' + str(response.text)
        else:
            results = '未知状态->' + str(response.text)
        return results

    def query_balance(self, info):
        info = ast.literal_eval(info.encode("utf-8"))
        app_id = info['app_id']
        params = {
            'MerchantNo': app_id,
            'Timestamp': local_now().strftime('%Y%m%d%H%M%S'),
        }
        params['Sign'] = generate_draw_sign(params, _get_api_key(app_id))
        _LOGGER.info('kvpay balance query data: %s', json.dumps(params))
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        response = requests.post(_get_balance_gateway(app_id), data=params, timeout=3, headers=headers, verify=False)
        _LOGGER.info("kvpay balance query rsp data: %s %s", response.status_code, response.text)
        if response.status_code != 200:
            raise ParamError('kvpay query_agent_pay error')
        data = json.loads(response.text)['data']
        return str(
            '总金额' + str(float(data['t_amount'])) + ', ' + '可提金额' + str(float(data['u_amount'])) + ', ' + '冻结金额' + str(
                float(data['f_amount'])))


handler = KvPayHandler()
